package com.i2works.smartluolong.manage.shiro;

import com.google.common.collect.Sets;
import com.i2works.smartluolong.manage.entity.admin.AdminResDO;
import com.i2works.smartluolong.manage.entity.admin.AdminResQuery;
import com.i2works.smartluolong.manage.entity.admin.AdminUserDO;
import com.i2works.smartluolong.manage.entity.admin.AdminUserQuery;
import com.i2works.smartluolong.manage.service.admin.IAdminResService;
import com.i2works.smartluolong.manage.service.admin.IAdminRoleService;
import com.i2works.smartluolong.manage.service.admin.IAdminUserService;
import com.i2works.smartluolong.utils.exception.ServiceException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * 自定义shiro权限realm
 *
 * @author koal
 * @className SmartMasterRealm
 * @email koal@vip.qq.com
 * @date 2016/1/7 19:34
 */


public class SmartMasterRealm extends AuthorizingRealm {

    @Autowired
    private IAdminUserService adminUserService;
    @Autowired
    private IAdminRoleService adminRoleService;
    @Autowired
    private IAdminResService adminResService;

//    @Autowired
//    private SessionDAO sessionDAO;
//    @Autowired
//    private RememberMeManager rememberMeManager;
//    @Autowired
//    CookieRememberMeManager cookieRememberMeManager;

    private SecureRandomNumberGenerator generator = new SecureRandomNumberGenerator();

    private final Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 权限认证《获取授权URL连接》
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        AdminUserDO adminUser = (AdminUserDO) SecurityUtils.getSubject().getPrincipals().iterator().next();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        try {
            //设置资源
            AdminResQuery resQuery = new AdminResQuery();
            resQuery.setUserId(adminUser.getId());
            resQuery.setIsSystem(adminUser.getIsSystem());
            Set<AdminResDO> resUserSet = adminResService.queryUserResList(resQuery);
            Set<String> resSet = Sets.newLinkedHashSet();
            for (AdminResDO adminResDO : resUserSet) {
                resSet.add(adminResDO.getResCode());
            }
            info.setStringPermissions(resSet);
//            //设置角色(如果不进行角色判断，可不设置)
//            AdminRoleQuery roleQuery = new AdminRoleQuery();
//            roleQuery.setUserId(userId);
//            Set<AdminRoleDO> roleUserSet = adminRoleService.queryList(roleQuery);
//            Set<String> roleSet = Sets.newLinkedHashSet();
//            for (AdminRoleDO adminRoleDO : roleUserSet) {
//                roleSet.add(adminRoleDO.getRoleKey());
//            }
//             info.setRoles(roleSet);
        } catch (ServiceException e) {
            e.printStackTrace();
        }
        return info;
    }

    /**
     * 授权认证《获取权限角色》
     * 通过账号等账号信息，获取数据库账号信息，写入SimpleAuthenticationInfo发送到前台进行对比
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName = (String) token.getPrincipal();
        AdminUserQuery userQuery = new AdminUserQuery();
        userQuery.setUserName(userName);
        AdminUserDO adminUser = null;
        try {
            //登录前获取当前用户是否已经登录了，如果登录就踢出他处状态，并在本次登录成功。
            //获取当前已登录的用户session列表
//            Collection<Session> sessions = sessionDAO.getActiveSessions();
//            for (Session session : sessions) {
//                //清除该用户以前登录时保存的session
//                Object attribute = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
//                if (null != attribute) {
//                    SimplePrincipalCollection principalCollection = (SimplePrincipalCollection) attribute;
//                    for (Object object : principalCollection) {
//                        if (object != null) {
//                            AdminUserDO sessionUser = (AdminUserDO) object;
//                            logger.error(sessionUser.getUserName());
//                            if (StringUtils.equalsIgnoreCase(userName, sessionUser.getUserName())) {
//                                // fixme session清除(无效)
//                                clearCachedAuthorizationInfo(principalCollection);
//                                clearCachedAuthenticationInfo(principalCollection);
//                                session.setTimeout(-1000);
//                                sessionDAO.delete(session);
//                                //必须重新根据ID获取session
//                                Session readSession = sessionDAO.readSession(session.getId());
//                                if (readSession != null) {
//                                    session.setAttribute(ConstantParam.SESSION_FORCE_LOGOUT_KEY, Boolean.TRUE);
//                                }
//                            }
//                        }
//                    }
//                }
//            }

            adminUser = adminUserService.query(userQuery);
        } catch (ServiceException e) {
            e.printStackTrace();
            logger.error("YunWebRealm.doGetAuthorizationInfo权限授权出错:", e.getMessage());
        }
        if (adminUser == null) {
            throw new UnknownAccountException();//没找到帐号
        }
        if (adminUser.getStatus() == 0) {
            throw new LockedAccountException();//锁定
        }
        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                adminUser, //用户信息，方便页面使用 <shiro:principal property="nickName"/>调用
                adminUser.getPassword(), //密码
                ByteSource.Util.bytes(adminUser.getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );
        // 当验证都通过后，把用户信息放在session里
        Session session = SecurityUtils.getSubject().getSession();
        session.setAttribute("user", adminUser);
        session.setAttribute("userId", adminUser.getId());
        session.setAttribute("userName", adminUser.getUserName());
        session.setAttribute("nickName", adminUser.getNickName());
        return authenticationInfo;
    }

    /**
     * 清理授权缓存
     */
    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {

        super.clearCachedAuthorizationInfo(principals);
        System.err.println("清理授权缓存");
    }

    /**
     * 清理认证缓存
     * 由于认证缓存默认key存的是user的对象，所以无法清除。
     * 解决办法就是将key的user对象换成user的账号字符串
     */
    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {

        AdminUserDO adminUser = (AdminUserDO) principals.getPrimaryPrincipal();
        SimplePrincipalCollection spc = new SimplePrincipalCollection(adminUser.getUserName(), getName());
        super.clearCachedAuthenticationInfo(spc);
        System.err.println("清理认证缓存");
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    private void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    private void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }
}
